// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.warehouse.viewers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.dengues.commons.IDenguesCoreContants;
import org.dengues.commons.IDenguesSharedImage;
import org.dengues.commons.utils.ImageUtil;
import org.dengues.core.actions.AbstractAction;
import org.dengues.core.warehouse.ENavNodeType;
import org.dengues.core.warehouse.IWarehouseNode;
import org.dengues.core.warehouse.IWarehouseObject;
import org.dengues.core.warehouse.IWarehouseView;
import org.dengues.ui.tooltip.WarehouseNodeToolTip;
import org.dengues.warehouse.i18n.Messages;
import org.dengues.warehouse.models.FolderWarehouseNode;
import org.dengues.warehouse.models.WarehouseNode;
import org.dengues.warehouse.viewers.action.ClearTrashAction;
import org.dengues.warehouse.viewers.action.DeleteAction;
import org.dengues.warehouse.viewers.action.DeleteForeverAction;
import org.dengues.warehouse.viewers.action.EditPropertiesAction;
import org.dengues.warehouse.viewers.action.OpenPrefsSettingsAction;
import org.dengues.warehouse.viewers.action.RestoreAction;
import org.dengues.warehouse.viewers.database.CreateDatabaseAction;
import org.dengues.warehouse.viewers.database.CreateDbQueryAction;
import org.dengues.warehouse.viewers.database.EditDatabaseAction;
import org.dengues.warehouse.viewers.database.ReadRealDatabaseAction;
import org.dengues.warehouse.viewers.database.SynchronizeDbFromConnAction;
import org.dengues.warehouse.viewers.folder.CreateFolderAction;
import org.dengues.warehouse.viewers.process.CreateProcessAction;
import org.dengues.warehouse.viewers.process.EditProcessAction;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.TreeExpansionEvent;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2008-1-7 qiang.zhang $
 * 
 */
public class WarehouseView extends ViewPart implements IWarehouseView, ITabbedPropertySheetPageContributor {

    public static final String ID = VIEW_ID;

    private static WarehouseTreeViewer viewer;

    public static WarehouseNode root = new WarehouseNode(null, null, ENavNodeType.SYSTEM_FOLDER);

    private WarehouseNodeToolTip nodeToolTip;

    private final Separator separator = new Separator(IWorkbenchActionConstants.MB_ADDITIONS);

    protected List<AbstractAction> allActions;

    /**
     * This is a callback that will allow us to create the viewer and initialize it.
     */
    @Override
    public void createPartControl(Composite parent) {
        viewer = new WarehouseTreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        WarehouseViewProvider denguesViewProvider = new WarehouseViewProvider(this);
        viewer.setContentProvider(denguesViewProvider);
        viewer.setLabelProvider(denguesViewProvider);
        viewer.setSorter(new WarehouseViewNameSorter());
        IViewSite viewSite = getViewSite();
        viewer.setInput(viewSite);
        getSite().setSelectionProvider(viewer);

        makeActions();
        hookContextMenu();
        contributeToActionBars();
        WarehouseViewFactory.initDragAndDrop(viewer);
        hookDoubleClickAction();
        nodeToolTip = new WarehouseNodeToolTip(viewer.getControl());
        setPartName(Messages.getString("WarehouseView.Title.Name")); //$NON-NLS-1$
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "hookDoubleClickAction".
     */
    private void hookDoubleClickAction() {
        viewer.getTree().addMouseListener(new MouseAdapter() {

            @Override
            public void mouseDoubleClick(MouseEvent e) {
                ISelection selection = viewer.getSelection();
                if (selection instanceof IStructuredSelection) {
                    IStructuredSelection s = (IStructuredSelection) selection;
                    if (s.toArray().length == 1) {
                        WarehouseNode node2 = (WarehouseNode) s.getFirstElement();
                        ENavNodeType nodeType = node2.getNodeType();
                        if (nodeType.compareTo(ENavNodeType.SIMPLE_FOLDER) == 0
                                | nodeType.compareTo(ENavNodeType.SYSTEM_FOLDER) == 0) {
                            boolean isExpandable = viewer.getExpandedState(node2);
                            viewer.setExpandedState(node2, !isExpandable);
                            viewer.refresh();
                            return;
                        }
                        IWarehouseObject object = node2.getObject();
                        if (object != null) {
                            Object data = object.getData();
                            for (AbstractAction abstractAction : allActions) {
                                boolean doubleClick = abstractAction.isDoubleClick();
                                if (doubleClick && abstractAction.getDoubleClickClass() != null) {
                                    if (abstractAction.getDoubleClickClass().isInstance(data)) {
                                        abstractAction.setEnable();
                                        if (abstractAction.isEnabled()) {
                                            abstractAction.run();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

        });
        viewer.addTreeListener(new ITreeViewerListener() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.ITreeViewerListener#treeExpanded(org.eclipse.jface.viewers.TreeExpansionEvent)
             */
            public void treeExpanded(TreeExpansionEvent event) {
                if (event.getElement() instanceof FolderWarehouseNode) {
                    viewer.setExpandedState(event.getElement(), true);
                    viewer.refresh(event.getElement(), true);
                }
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.ITreeViewerListener#treeCollapsed(org.eclipse.jface.viewers.TreeExpansionEvent)
             */
            public void treeCollapsed(TreeExpansionEvent event) {
                if (event.getElement() instanceof FolderWarehouseNode) {
                    viewer.setExpandedState(event.getElement(), false);
                    viewer.refresh(event.getElement(), true);
                }
            }

        });
        viewer.getTree().addFocusListener(new FocusAdapter() {

            @Override
            public void focusLost(FocusEvent e) {
                nodeToolTip.hide();
            }
        });

        viewer.getTree().addKeyListener(new KeyListener() {

            public void keyPressed(KeyEvent e) {
                if (e.keyCode == SWT.ESC) {
                    nodeToolTip.hide();
                }
            }

            public void keyReleased(KeyEvent e) {
            }

        });

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "makeActions".
     */
    private void makeActions() {
        refreshAction = new RefreshViewAction();
        allActions = new ArrayList<AbstractAction>();
        allActions.add(new CreateDatabaseAction());
        allActions.add(new CreateProcessAction());
        allActions.add(new ClearTrashAction());
        allActions.add(new EditProcessAction());
        allActions.add(new EditDatabaseAction());
        allActions.add(new DeleteAction());
        allActions.add(new DeleteForeverAction());
        allActions.add(new EditPropertiesAction());
        allActions.add(new CreateFolderAction());
        allActions.add(new OpenPrefsSettingsAction());
        allActions.add(new RestoreAction());
        allActions.add(new ReadRealDatabaseAction());
        allActions.add(new CreateDbQueryAction());
        allActions.add(new SynchronizeDbFromConnAction());
        allActions.addAll(AbstractAction.getAllActionsFromExtension());
        Collections.sort(allActions, new Comparator<AbstractAction>() {

            public int compare(AbstractAction o1, AbstractAction o2) {
                return o1.getLevel() > o2.getLevel() ? 1 : -1;
            }
        });
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    @Override
    public void setFocus() {
        if (!viewer.getControl().isDisposed()) {
            viewer.getControl().setFocus();
        }
    }

    public void hookContextMenu() {
        MenuManager menuMgr = new MenuManager(); //$NON-NLS-1$
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {

            public void menuAboutToShow(IMenuManager manager) {
                fillContextMenu(manager);
            }

            @SuppressWarnings("unchecked")//$NON-NLS-1$
            private void fillContextMenu(IMenuManager manager) {
                for (AbstractAction abstractAction : allActions) {
                    abstractAction.setEnable();
                    if (abstractAction.isEnabled()) {
                        String subItem = abstractAction.getSubItem();
                        boolean found = false;
                        MenuManager menuManager = null;
                        if (subItem != null && subItem.length() > 0) {
                            IContributionItem[] items = manager.getItems();
                            for (IContributionItem ci : items) {
                                if (ci instanceof Separator) {
                                    if (subItem.equals(ci.getId())) {
                                        found = true;
                                        break;
                                    }
                                }
                            }
                            for (IContributionItem ci : items) {
                                if (ci instanceof MenuManager) {
                                    if (subItem.equals(((MenuManager) ci).getMenuText())) {
                                        menuManager = (MenuManager) ci;
                                    }
                                }
                            }
                            if (!found) {
                                manager.add(new Separator(subItem));
                                menuManager = new MenuManager(subItem);
                                menuManager.add(abstractAction);
                                manager.appendToGroup(subItem, menuManager);
                            } else {
                                menuManager.add(abstractAction);
                            }
                        } else {
                            manager.add(abstractAction);
                        }
                    }
                }
                manager.add(separator);
            }
        });
        Menu contextMenu = menuMgr.createContextMenu(viewer.getTree());
        viewer.getTree().setMenu(contextMenu);
    }

    public void contributeToActionBars() {
        IActionBars actionBars = getViewSite().getActionBars();
        fillLocalPullDown(actionBars.getMenuManager());
        fillLocalToolBar(actionBars.getToolBarManager());
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "fillLocalToolBar".
     * 
     * @param toolBarManager
     */
    private void fillLocalToolBar(IToolBarManager toolBarManager) {
        toolBarManager.add(refreshAction);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "fillLocalPullDown".
     * 
     * @param menuManager
     */
    private void fillLocalPullDown(IMenuManager menuManager) {

    }

    private RefreshViewAction refreshAction;

    /**
     * Qiang.Zhang.Adolf@gmail.com WarehouseView class global comment. Detailled comment <br/>
     * 
     * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
     * 
     */
    private class RefreshViewAction extends Action {

        /**
         * zx DenguesNavView.RefreshViewAction constructor comment.
         */
        public RefreshViewAction() {
            super(Messages.getString("WarehouseView.RefreshAction.Label")); //$NON-NLS-1$
            setImageDescriptor(ImageUtil.getDescriptor(IDenguesSharedImage.ACTION_REFRESH));
            setTitleToolTip(Messages.getString("WarehouseView.RefreshAction.TitleToolTip")); //$NON-NLS-1$
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.action.Action#run()
         */
        @Override
        public void run() {
            root = new WarehouseNode(null, null, ENavNodeType.SYSTEM_FOLDER);
            viewer.refresh();
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseView#refresh()
     */
    public void refresh(Object node) {
        root = new WarehouseNode(null, null, ENavNodeType.SYSTEM_FOLDER);
        viewer.refresh();
        viewer.setSelection(new TreeSelection());
        if (node != null) {
            if (((WarehouseNode) node).getParent() != null) {
                viewer.setExpandedState(((WarehouseNode) node).getParent(), true);
            }
        }
    }

    public void refresh() {
        root = new WarehouseNode(null, null, ENavNodeType.SYSTEM_FOLDER);
        viewer.refresh();
        viewer.setSelection(new TreeSelection());
    }

    public WarehouseNode getRoot() {
        return root;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor#getContributorId()
     */
    public String getContributorId() {
        return IDenguesCoreContants.ID_VIEW_PROP;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
     */
    @Override
    public Object getAdapter(Class adapter) {
        if (adapter == IPropertySheetPage.class) {
            return new TabbedPropertySheetPage(this);
        }
        return super.getAdapter(adapter);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseView#expand(java.lang.Object)
     */
    public boolean isExpanded(Object node) {
        return viewer.getExpandedState(node);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseView#expand(org.dengues.core.warehouse.IWarehouseNode, boolean)
     */
    public void expand(IWarehouseNode object, boolean state) {
        if (object == null) {
            return;
        }
        viewer.setExpandedState(object, state);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.warehouse.IWarehouseView#getTreeView()
     */
    public TreeViewer getTreeView() {
        return viewer;
    }
}
